#!/usr/bin/env node

/**
 * MCP Music Player Server for Termux
 * Provides local music playback tools via MCP protocol
 * Version: 0.1.0 - Using @modelcontextprotocol/sdk
 */

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import { spawn, execSync } from 'child_process';
import { existsSync, readdirSync } from 'fs';
import { join, resolve, extname } from 'path';
import { fileURLToPath } from 'node:url';

// Simple logger utility
const logger = {
	info: (message) => {
		const timestamp = new Date().toISOString();
		console.error(`${timestamp} - MusicPlayer - INFO - ${message}`);
	},
	error: (message) => {
		const timestamp = new Date().toISOString();
		console.error(`${timestamp} - MusicPlayer - ERROR - ${message}`);
	},
	debug: (message) => {
		const timestamp = new Date().toISOString();
		console.error(`${timestamp} - MusicPlayer - DEBUG - ${message}`);
	},
};

// Music player class for Termux environment
class TermuxMusicPlayer {
	constructor() {
		this.currentProcess = null;
		this.isPlaying = false;
		// Multiple possible music directories in Termux
		this.musicDirs = [
			resolve('./music')
		];
		this.currentMusicDir = null;
		this.findMusicDirectory();
	}

	findMusicDirectory() {
		for (const dir of this.musicDirs) {
			if (existsSync(dir)) {
				this.currentMusicDir = dir;
				logger.info(`Found music directory: ${dir}`);
				break;
			}
		}
		
		if (!this.currentMusicDir) {
			logger.warn('No music directory found. Using current directory.');
			this.currentMusicDir = resolve('.');
		}
	}

	// Check if termux-api is available
	checkTermuxAPI() {
		try {
			execSync('which termux-media-player', { stdio: 'ignore' });
			return true;
		} catch {
			return false;
		}
	}

	// Get available music files
	listMusicFiles() {
		try {
			if (!existsSync(this.currentMusicDir)) {
				return [];
			}
			
			const files = readdirSync(this.currentMusicDir);
			const audioExtensions = ['.mp3', '.wav', '.ogg', '.m4a', '.flac', '.aac'];
			
			return files.filter(file => 
				audioExtensions.includes(extname(file).toLowerCase())
			);
		} catch (error) {
			logger.error(`Error listing music files: ${error.message}`);
			return [];
		}
	}

	play(musicName) {
		try {
			// Stop currently playing music if any
			this.stop();

			// Construct full path to music file
			const musicPath = join(this.currentMusicDir, musicName);
			
			// Check if file exists
			if (!existsSync(musicPath)) {
				const availableFiles = this.listMusicFiles();
				return {
					success: false,
					error: `Music file not found: ${musicPath}`,
					availableFiles: availableFiles,
					suggestion: availableFiles.length > 0 ? 
						`Available files: ${availableFiles.join(', ')}` : 
						'No music files found in directory'
				};
			}

			logger.info(`Attempting to play: ${musicPath}`);

			let command, args;
			
			// Try termux-media-player first (most reliable in Termux)
			if (this.checkTermuxAPI()) {
				command = 'termux-media-player';
				args = ['play', musicPath];
			} else {
				// Fallback to other players that might be available in Termux
				// Try ffplay (from ffmpeg package)
				//command = 'ffplay';
				//args = ['-nodisp', '-autoexit', musicPath];
				
				// Alternative: Use mpv if available
				command = 'mpv';
				args = ['--no-video', musicPath];
			}

			logger.info(`Using command: ${command} ${args.join(' ')}`);

			// Spawn the audio player process
			this.currentProcess = spawn(command, args, {
				stdio: 'ignore',
				detached: false // Keep attached to manage properly
			});

			this.currentProcess.on('error', (error) => {
				logger.error(`Failed to start audio player: ${error.message}`);
				this.isPlaying = false;
				
				// Try fallback if termux-media-player fails
				if (command === 'termux-media-player') {
					logger.info('Trying fallback player...');
					this.tryFallbackPlayer(musicPath);
				}
			});

			this.currentProcess.on('exit', (code) => {
				logger.info(`Audio player exited with code: ${code}`);
				this.isPlaying = false;
			});

			this.isPlaying = true;
			
			return {
				success: true,
				message: `Now playing: ${musicName}`,
				filePath: musicPath,
				player: command
			};

		} catch (error) {
			logger.error(`Playback error: ${error.message}`);
			return {
				success: false,
				error: `Playback failed: ${error.message}`
			};
		}
	}

	tryFallbackPlayer(musicPath) {
		try {
			// Try ffplay
			this.currentProcess = spawn('ffplay', ['-nodisp', '-autoexit', musicPath], {
				stdio: 'ignore',
				detached: false
			});
			
			this.currentProcess.on('error', (error) => {
				logger.error(`Fallback player also failed: ${error.message}`);
			});
			
			this.currentProcess.on('exit', (code) => {
				this.isPlaying = false;
			});
			
			this.isPlaying = true;
		} catch (error) {
			logger.error(`All playback methods failed: ${error.message}`);
		}
	}

	stop() {
		if (this.currentProcess) {
			try {
				this.currentProcess.kill();
				logger.info('Stopped current playback');
			} catch (error) {
				logger.debug(`Stop error: ${error.message}`);
			}
			this.currentProcess = null;
			this.isPlaying = false;
		}
		
		// Also stop termux-media-player if it's running
		if (this.checkTermuxAPI()) {
			try {
				spawn('termux-media-player', ['stop'], {
					stdio: 'ignore',
					detached: true
				});
			} catch (error) {
				// Ignore errors when stopping
			}
		}
		
		return {
			success: true,
			message: 'Playback stopped'
		};
	}

	getStatus() {
		return {
			isPlaying: this.isPlaying,
			musicDirectory: this.currentMusicDir,
			availablePlayers: this.checkTermuxAPI() ? ['termux-media-player', 'ffplay'] : ['ffplay'],
			availableFiles: this.listMusicFiles()
		};
	}
}

// Create music player instance
const musicPlayer = new TermuxMusicPlayer();

// Create MCP server instance using the official SDK
const server = new McpServer({
	name: "TermuxMusicPlayer",
	version: "0.1.0",
});

// Register play_music tool
server.tool(
	"play_music",
	"Play a music file from the local music directory in Termux environment. Supports termux-media-player and ffplay.",
	{
		musicName: z
			.string()
			.describe("Name of the music file to play (e.g., 'song.mp3', 'track.wav')"),
	},
	async ({ musicName }) => {
		try {
			const result = musicPlayer.play(musicName);
			
			if (result.success) {
				logger.info(`Successfully started playback: ${musicName}`);
				return {
					content: [
						{
							type: "text",
							text: JSON.stringify(result),
						},
					],
				};
			} else {
				logger.error(`Failed to play music: ${result.error}`);
				return {
					content: [
						{
							type: "text",
							text: JSON.stringify(result),
						},
					],
					isError: true,
				};
			}
		} catch (error) {
			logger.error(`Music playback error: ${error.message}`);
			return {
				content: [
					{
						type: "text",
						text: JSON.stringify({
							success: false,
							error: error.message,
						}),
					},
				],
				isError: true,
			};
		}
	}
);

// Register stop_music tool
server.tool(
	"stop_music",
	"Stop currently playing music",
	{},
	async () => {
		try {
			const result = musicPlayer.stop();
			logger.info("Playback stopped");
			
			return {
				content: [
					{
						type: "text",
						text: JSON.stringify(result),
					},
				],
			};
		} catch (error) {
			logger.error(`Stop music error: ${error.message}`);
			return {
				content: [
					{
						type: "text",
						text: JSON.stringify({
							success: false,
							error: error.message,
						}),
					},
				],
				isError: true,
			};
		}
	}
);

// Register music_status tool
server.tool(
	"music_status",
	"Get current music playback status and available files",
	{},
	async () => {
		try {
			const status = musicPlayer.getStatus();
			logger.debug(`Music status: ${JSON.stringify(status)}`);
			
			return {
				content: [
					{
						type: "text",
						text: JSON.stringify({
							success: true,
							status: status
						}),
					},
				],
			};
		} catch (error) {
			logger.error(`Status check error: ${error.message}`);
			return {
				content: [
					{
						type: "text",
						text: JSON.stringify({
							success: false,
							error: error.message,
						}),
					},
				],
				isError: true,
			};
		}
	}
);

// Register list_music tool
server.tool(
	"list_music",
	"List available music files in the music directory",
	{},
	async () => {
		try {
			const files = musicPlayer.listMusicFiles();
			const status = musicPlayer.getStatus();
			
			const result = {
				success: true,
				musicDirectory: status.musicDirectory,
				availableFiles: files,
				totalFiles: files.length
			};
			
			logger.info(`Listed ${files.length} music files`);
			
			return {
				content: [
					{
						type: "text",
						text: JSON.stringify(result),
					},
				],
			};
		} catch (error) {
			logger.error(`List music error: ${error.message}`);
			return {
				content: [
					{
						type: "text",
						text: JSON.stringify({
							success: false,
							error: error.message,
						}),
					},
				],
				isError: true,
			};
		}
	}
);

// Start the server if this file is run directly
async function main() {
	logger.info("Starting MCP Termux Music Player server");
	logger.info(`Current music directory: ${musicPlayer.currentMusicDir}`);

	const transport = new StdioServerTransport();
	await server.connect(transport);

	logger.info("MCP Termux Music Player server is running on stdio");
}

// Run the server if this file is executed directly
const currentFile = fileURLToPath(import.meta.url);
const argFile = process.argv[1] ? resolve(process.argv[1]) : null;

if (argFile && currentFile === argFile) {
	main().catch((error) => {
		logger.error(`Failed to start server: ${error.message}`);
		process.exit(1);
	});
}

export default server;